home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / jaq / dist / queue.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-15  |  11.1 KB  |  425 lines

  1. /*
  2.  * queue.c --
  3.  *
  4.  *     Queue package for Jaquith archive system
  5.  *  
  6.  * Copyright 1992 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  *                                                           
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/queue.c,v 1.0 91/01/07 18:02:37 mottsmth Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include "jaquith.h"
  22.  
  23. /*
  24.  * Rather than allocate and free nodes all the time as items are   
  25.  * enqueued and dequeued, we'll recycle them onto a freeList 
  26.  * for later use.                                            
  27.  */                                                           
  28. static Q_Node *freeList = NULL;
  29. static int freeCnt = 0;
  30.  
  31. #define FREEMAX 1000
  32.  
  33.  
  34. /*
  35.  *----------------------------------------------------------------------
  36.  *                                                           
  37.  * Q_Create -- create and initialize a new FIFO queue.          
  38.  *                                                           
  39.  * Results:
  40.  *    returns an opaque handle to the user for later use.
  41.  *
  42.  * Side effects:
  43.  *      Allocates a queue object.
  44.  *                                                           
  45.  *----------------------------------------------------------------------
  46.  */
  47.  
  48. Q_Handle *
  49. Q_Create(name, freeData)
  50.     char *name;               /* name of queue for debugging */
  51.     int freeData;             /* pass datum to Free when deallocating */
  52. {
  53.     Q_Handle *qPtr;                 
  54.  
  55.     qPtr = (Q_Handle *) MEM_ALLOC("Q_Create", sizeof(Q_Handle));
  56.     qPtr->head = NULL;
  57.     qPtr->tail = NULL;
  58.     qPtr->count = 0;
  59.     qPtr->freeData = freeData;
  60.     qPtr->name = (char *) MEM_ALLOC("Q_Create", strlen(name)+1);
  61.     strcpy(qPtr->name, name);
  62.     return (qPtr);
  63.  
  64. }
  65.  
  66.  
  67. /*
  68.  *----------------------------------------------------------------------
  69.  *                                                           
  70.  * Q_Destroy -- Destroy a queue.                              
  71.  *
  72.  * Results:
  73.  *    None.
  74.  *
  75.  * Side effects:
  76.  *      Deallocates a queue object.
  77.  *                                                           
  78.  *----------------------------------------------------------------------
  79.  */
  80.  
  81. void
  82. Q_Destroy(qPtr)
  83.     Q_Handle *qPtr;           /* queue handle */
  84. {
  85.     Q_Node *nodePtr;
  86.     Q_Node *tmpPtr;
  87.  
  88.     if (!qPtr) {
  89.         fprintf(stderr, "Q_Destroy: queue pointer argument is NULL!\n");
  90.         exit(-1);
  91.     }
  92.  
  93.     nodePtr = qPtr->head;
  94.  
  95.     while (nodePtr != NULL) {
  96.     if (qPtr->freeData) {
  97.         MEM_FREE("Q_Destroy", nodePtr->datum);
  98.     }
  99.     if (freeCnt > FREEMAX) {
  100.         MEM_FREE("Q_Destroy", nodePtr);
  101.     } else {
  102.         freeCnt++;
  103.         tmpPtr = nodePtr->link;
  104.         nodePtr->link = freeList;
  105.         freeList = nodePtr;
  106.         nodePtr = tmpPtr;
  107.     }
  108.     }
  109.  
  110.     MEM_FREE("Q_Destroy", qPtr->name);
  111.     MEM_FREE("Q_Destroy", (char *)qPtr);
  112.  
  113. }
  114.  
  115.  
  116. /*
  117.  *----------------------------------------------------------------------
  118.  *                                                           
  119.  * Q_Add -- Add a new element to queue in priority order      
  120.  *                                                           
  121.  * Results:
  122.  *    None.
  123.  *
  124.  * Side effects:
  125.  *      None.
  126.  *
  127.  * priority tells where to add element:                      
  128.  *   0            : at head                                  
  129.  *   positive int : at appropriate place in queue            
  130.  *                  (lower numbers nearer head of queue)     
  131.  *   MAX_INT      : at tail                                  
  132.  *                                                           
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. void
  137. Q_Add(qPtr, datum, priority)
  138.     Q_Handle *qPtr;           /* queue handle */
  139.     Q_ClientData datum;       /* client datum to enqueue */
  140.     int priority;             /* priority of item */
  141. {
  142.     Q_Node *nodePtr;
  143.     Q_Node *frontPtr, *backPtr;
  144.  
  145.     if (!qPtr) {
  146.         fprintf(stderr, "Q_Add: queue pointer argument is NULL!\n");
  147.         exit(-1);
  148.     }
  149.  
  150.     if (freeCnt > 0) {
  151.     freeCnt--;
  152.         nodePtr = freeList;
  153.     freeList = nodePtr->link;
  154.     } else {
  155.         nodePtr = (Q_Node *) MEM_ALLOC("Q_Add", sizeof(Q_Node));
  156.     }
  157.  
  158.     nodePtr->datum = datum;
  159.     nodePtr->priority = priority;
  160.  
  161.     if (priority == Q_TAILQ) {
  162.         nodePtr->link = NULL;
  163.     if (qPtr->head) {
  164.         qPtr->tail->link = nodePtr;
  165.     } else {
  166.         qPtr->head = nodePtr;
  167.     }
  168.     qPtr->tail = nodePtr;
  169.     } else if (priority == Q_HEADQ) {
  170.     if (!(nodePtr->link = qPtr->head)) {
  171.         qPtr->tail = nodePtr;
  172.     }
  173.         qPtr->head = nodePtr;
  174.     } else if (priority > 0) {
  175.         frontPtr = qPtr->head;
  176.     backPtr = NULL;
  177.     while (frontPtr != NULL) {
  178.         if (frontPtr->priority > priority) break;
  179.         backPtr = frontPtr;
  180.         frontPtr = frontPtr->link;
  181.     }
  182.     if (backPtr) {
  183.         backPtr->link = nodePtr;
  184.     } else {
  185.         qPtr->head = nodePtr;
  186.     }
  187.     if (!(nodePtr->link = frontPtr)) {
  188.         qPtr->tail = nodePtr;
  189.     }
  190.     } else {
  191.         fprintf(stderr,"Q_Add: bad queueing priority: %d",priority);
  192.     exit(-1);
  193.     }
  194.  
  195.     qPtr->count++;
  196. }
  197.  
  198.  
  199. /*
  200.  *----------------------------------------------------------------------
  201.  *                                                           
  202.  * Q_Remove -- Remove an element from the head of the queue.  
  203.  *                                                           
  204.  * Results:
  205.  *    None.
  206.  *
  207.  * Side effects:
  208.  *      None.
  209.  *
  210.  * If the queue is empty the routine aborts.                 
  211.  *                                                           
  212.  *----------------------------------------------------------------------
  213.  */
  214.  
  215. Q_ClientData
  216. Q_Remove(qPtr)
  217.     Q_Handle *qPtr;           /* queue handle */
  218. {
  219.     Q_Node *nodePtr;
  220.     Q_ClientData datum;
  221.  
  222.     if (!qPtr) {
  223.         fprintf(stderr,"Q_Remove: queue pointer argument is NULL!\n");
  224.         exit(-1);
  225.     }
  226.  
  227.     if (!qPtr->head) {
  228.         fprintf(stderr,"Q_Remove: Queue '%s' is empty!\n", qPtr->name);
  229.         exit(-1);
  230.     }
  231.  
  232.     nodePtr = qPtr->head;
  233.     if (!(qPtr->head = nodePtr->link)) {
  234.     qPtr->tail = NULL;
  235.     }
  236.     qPtr->count--;
  237.     datum = nodePtr->datum;
  238.     nodePtr->link = freeList;
  239.     freeList = nodePtr;
  240.  
  241.     return (datum);
  242.  
  243. }
  244.  
  245.  
  246.  
  247. /*
  248.  *----------------------------------------------------------------------
  249.  *                                                           
  250.  * Q_Count -- return the number of elements in the queue.     
  251.  *
  252.  * Results:
  253.  *    Number of elements on the queue.
  254.  *
  255.  * Side effects:
  256.  *      None.
  257.  *                                                           
  258.  *----------------------------------------------------------------------
  259.  */
  260.  
  261. int
  262. Q_Count(qPtr)
  263.     Q_Handle *qPtr;           /* queue handle */
  264. {
  265.     if (!qPtr) {
  266.         fprintf(stderr,"Q_Count: queue pointer argument is NULL!\n");
  267.         exit(-1);
  268.     }
  269.  
  270.     return (qPtr->count);
  271.  
  272. }
  273.  
  274.  
  275.  
  276. /*
  277.  *----------------------------------------------------------------------
  278.  *                                                           
  279.  * Q_Peek -- return 1st item in queue w/o removing it         
  280.  * 
  281.  * Results:
  282.  *    Ptr to item at head of queue.
  283.  *
  284.  * Side effects:
  285.  *      None.
  286.  *                                                           
  287.  *----------------------------------------------------------------------
  288.  */
  289.  
  290. Q_ClientData
  291. Q_Peek(qPtr)
  292.     Q_Handle *qPtr;           /* queue handle */
  293. {
  294.  
  295.     if (!qPtr) {
  296.         fprintf(stderr,"Q_Peek: queue pointer argument is NULL!\n");
  297.         exit(-1);
  298.     }
  299.  
  300.     if (!qPtr->head) {
  301.         fprintf(stderr,"Q_Peek: Queue '%s' is empty!\n", qPtr->name);
  302.         exit(-1);
  303.     }
  304.  
  305.     return(qPtr->head->datum);
  306.  
  307. }
  308.  
  309.  
  310. /*
  311.  *----------------------------------------------------------------------
  312.  *                                                           
  313.  * Q_Print -- Print all the items in the queue (for debugging)
  314.  *                                                           
  315.  * Results:
  316.  *    None.
  317.  *
  318.  * Side effects:
  319.  *      Items are printed on the specified channel, or stderr.
  320.  *                                                           
  321.  *----------------------------------------------------------------------
  322.  */
  323.  
  324. void
  325. Q_Print(qPtr, fd)
  326.     Q_Handle *qPtr;           /* queue handle */
  327.     FILE *fd;                 /* file descriptor for output */
  328. {
  329.     Q_Node *nodePtr;
  330.     int i = 0;
  331.  
  332.     if (!qPtr) {
  333.         fprintf(stderr,"Q_Print: queue pointer argument is NULL!\n");
  334.         exit(-1);
  335.     }
  336.  
  337.     if (!fd) fd = stderr;
  338.     fprintf(fd,"Q_Print: Queue '%s' has %d items",
  339.         qPtr->name, qPtr->count);
  340.  
  341.     for (nodePtr=qPtr->head; nodePtr != NULL; nodePtr=nodePtr->link) {
  342.        if (!(i++ % 4)) fprintf(fd,"\n\t");
  343.        fprintf(fd, "  node %08x (datum %08x)", nodePtr, nodePtr->datum);
  344.     }
  345.     fprintf(fd,"\n");
  346.  
  347. }
  348.  
  349.  
  350. /*
  351.  *----------------------------------------------------------------------
  352.  *                                                           
  353.  * Q_Iterate -- Call user-supplied callback function on each  
  354.  *             element in the queue.                         
  355.  *                                                           
  356.  * Results:
  357.  *    None.
  358.  *
  359.  * Side effects:
  360.  *    None.
  361.  * 
  362.  * The callback function is provided with:                   
  363.  *    qPtr  : so it knows what queue it's operating on        
  364.  *   datum  : for processing                                  
  365.  *   count  : # of items remaining in queue after this one    
  366.  *   callVal: Arbitray ptr provided by Q_Iterate caller.
  367.  *                                                           
  368.  * Callback routine must not call Q_Add or Q_Remove for this Q.
  369.  *                                                           
  370.  * We respond to the return code as follows:                 
  371.  *    = Q_ITER_REMOVE_STOP : remove item from queue and stop
  372.  *    = Q_ITER_REMOVE_CONT : remove item from queue and continue 
  373.  *    = Q_ITER_STOP : stop
  374.  *    = Q_ITER_CONTINUE  : do nothing to the item and continue
  375.  *    other  : update priority field with given value and continue
  376.  *                                                           
  377.  *----------------------------------------------------------------------
  378. */
  379.  
  380. int
  381. Q_Iterate(qPtr, func, callVal)
  382.     Q_Handle *qPtr;           /* queue handle */
  383.     int (*func)();            /* callback function */
  384.     int *callVal;             /* arbitrary user-supplied datum */
  385. {
  386.     Q_Node *nodePtr, *backPtr;
  387.     int rc;
  388.     int retCode = 0;
  389.  
  390.     if (!qPtr) {
  391.         fprintf(stderr,"Q_Iterate: queue pointer argument is NULL!\n");
  392.         exit(-1);
  393.     }
  394.  
  395.     for (nodePtr=qPtr->head, backPtr = NULL;
  396.      nodePtr != NULL;
  397.      backPtr = nodePtr, nodePtr=nodePtr->link) {
  398.         rc = (*func)(qPtr, nodePtr->datum, &retCode, callVal);
  399.     if (rc == Q_ITER_STOP) {
  400.         break;
  401.     } else if (rc == Q_ITER_CONTINUE) {
  402.         /* do nothing */;
  403.     } else if ((rc == Q_ITER_REMOVE_CONT) ||
  404.            (rc == Q_ITER_REMOVE_STOP)) {
  405.         qPtr->count--;
  406.         if (nodePtr == qPtr->head)
  407.         qPtr->head = nodePtr->link;
  408.         else 
  409.         backPtr->link = nodePtr->link;
  410.         if (nodePtr == qPtr->tail) {
  411.         qPtr->tail = backPtr;
  412.         }
  413.         if (rc == Q_ITER_REMOVE_STOP) {
  414.         break;
  415.         }
  416.     } else {
  417.         nodePtr->priority = rc;
  418.     }
  419.     }
  420.  
  421.     return retCode;
  422.  
  423. }
  424.  
  425.